﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace CorporationWars
{
    public class Camera : GameComponent, IBase3DObject
    {
        public Vector3 Position { get; set; }
        public Vector3 Scale { get; set; }
        public Quaternion Rotation { get; set; }

        public BoundingBox Bounds { get { return new BoundingBox(Vector3.Transform(-Vector3.One, Matrix.CreateTranslation(Position)), Vector3.Transform(Vector3.One, Matrix.CreateTranslation(Position))); } }
        
        public Matrix World { get; set; }
        public Matrix View { get; set; }
        public Matrix Projection { get; set; }

        protected Viewport viewport;
        public Viewport Viewport
        {
            get { return viewport; }
            set { viewport = value; }
        }

        protected float minDepth { get; set; }
        protected float maxDepth { get; set; }

        public float MinDepth { get { return minDepth; } }
        public float MaxDepth { get { return maxDepth; } }

        public BoundingFrustum Frustum
        {
            get
            {
                return new BoundingFrustum(Matrix.Multiply(View, Projection));
            }
        }

        public Camera(Game game, float minDepth, float maxDepth)
            : base(game)
        {
            Position = Vector3.Zero;
            Scale = Vector3.One;
            Rotation = Quaternion.Identity;

            this.minDepth = minDepth;
            this.maxDepth = maxDepth;

            game.Components.Add(this);
            game.Services.AddService(this.GetType(), this);
        }

        public override void Initialize()
        {
            viewport = Game.GraphicsDevice.Viewport;
            viewport.MinDepth = minDepth;
            viewport.MaxDepth = maxDepth;
        }

        public override void Update(GameTime gameTime)
        {
            World = Matrix.CreateFromQuaternion(Rotation) * Matrix.CreateTranslation(Position);
            View = Matrix.Invert(World);

            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Viewport.AspectRatio, Viewport.MinDepth, Viewport.MaxDepth);

            base.Update(gameTime);
        }

        public virtual void Translate(Vector3 distance)
        {
            Position += Vector3.Transform(distance, Matrix.CreateFromQuaternion(Rotation));
        }
        public virtual void TranslateAA(Vector3 distance)
        {
            Position += Vector3.Transform(distance, Matrix.CreateFromQuaternion(Quaternion.Identity));
        }
        public virtual void Rotate(Vector3 axis, float angle)
        {
            axis = Vector3.Transform(axis, Matrix.CreateFromQuaternion(Rotation));
            Rotation = Quaternion.Normalize(Quaternion.CreateFromAxisAngle(axis, angle) * Rotation);
            Quaternion rot = Rotation;
            Game1.LockRotation(ref rot, Vector3.Forward);
            Rotation = rot;
        }
    }
}
